/*!
 Temelia - Sorting algorithms performance tests.

 Copyright (C) 2008 Ceata (http://cod.ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

// The performance test is based on the sample for the sorting algorithms

#include "include/performance.hpp"
#include "include/testutil.hpp"

extern "C"
{
#include <temelia/sort.h>
}

static int **generic_data;
static int *radix_data;
static unsigned int *number_data;

static void sort_init(int size)
{
	generic_data = (int **) malloc(size * sizeof(int *));

	// Copy size int pointers
	memcpy(generic_data, default_collection, size * sizeof(int *));

	radix_data = (int *) malloc(size * sizeof(int));

	for (int j = 0; j < size; j++)
		radix_data[j] = rand();

	int max_value;
	number_data = (unsigned int *) malloc(size * sizeof(unsigned int));

	if (size >= 256)
		max_value = 256;
	else
		max_value = size;

	for (int j = 0; j < size; j++)
		number_data[j] = rand() % max_value;
}

static void sort_destroy()
{
	free(generic_data);
	free(radix_data);
	free(number_data);
}

static void temelia_generic_sort(int size, void generic_sort_algorithm(
		void *generic_data, int size, void *key_at(void *generic_data,
				int index), void set_key_at(void *generic_data, int index,
				void *new_value), int compare(void *x, void *y, void *context),
		void *context), int compare(void *x, void *y, void *context),
		void *context, const char *generic_sort_name)
{
	generic_sort_algorithm(generic_data, size, my_key_at, my_set_key_at,
			compare, context);
	if (!is_sorted(generic_data, size, my_key_at, compare, context))
		report_error("sorting algorithm %s failed!\n", generic_sort_name);
}

static void temelia_bubble_sort(int n)
{
	temelia_generic_sort(n, bubble_sort, int_compare, NULL, "bubble_sort");
}

static void temelia_insertion_sort(int n)
{
	temelia_generic_sort(n, insertion_sort, int_compare, NULL, "insertion_sort");
}

static void temelia_merge_sort(int n)
{
	temelia_generic_sort(n, merge_sort, int_compare, NULL, "merge_sort");
}

static void temelia_quick_sort(int n)
{
	temelia_generic_sort(n, quick_sort, int_compare, NULL, "quick_sort");
}

static void temelia_selection_sort(int n)
{
	temelia_generic_sort(n, selection_sort, int_compare, NULL, "selection_sort");
}

static void temelia_shell_sort(int n)
{
	temelia_generic_sort(n, shell_sort, int_compare, NULL, "shell_sort");
}

static void temelia_heap_sort(int n)
{
	temelia_generic_sort(n, heap_sort, int_compare, NULL, "heap_sort");
}

static void temelia_gnome_sort(int n)
{
	temelia_generic_sort(n, gnome_sort, int_compare, NULL, "gnome_sort");
}

static void temelia_cocktail_sort(int n)
{
	temelia_generic_sort(n, cocktail_sort, int_compare, NULL, "cocktail_sort");
}

static int radix_compare(void *x, void *y, void *context)
{
	return (int) ((unsigned int) x - (unsigned int) y);
}

static void temelia_radix_sort(int n)
{
	radix_sort(radix_data, n, 10);
	if (!is_sorted(radix_data, n, my_key_at, radix_compare, NULL))
		report_error("sorting algorithm radix_sort failed!\n");
}

static void temelia_number_sort(int n)
{
	number_sort(number_data, n, n > 256 ? 256 : n);

	if (!is_sorted(number_data, n, my_key_at, radix_compare, NULL))
		report_error("sorting algorithm number_sort failed!\n");
}

static void temelia_bubble_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "bubble_sort", bubble_sort);
}

static void temelia_merge_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "merge_sort", merge_sort);
}

static void temelia_insertion_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "insertion_sort", insertion_sort);
}

static void temelia_quick_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "quick_sort", quick_sort);
}

static void temelia_selection_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "selection_sort", selection_sort);
}

static void temelia_shell_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "shell_sort", shell_sort);
}

static void temelia_heap_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "heap_sort", heap_sort);
}

static void temelia_gnome_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "gnome_sort", gnome_sort);
}

static void temelia_cocktail_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "cocktail_sort", cocktail_sort);
}

static void temelia_radix_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "radix_sort", radix_sort);

}

static void temelia_number_sort(TestUnit &testUnit, int tests)
{
#ifndef CLUSTER_RUNNING
	ntests = tests;
#endif
	GENERATE_TEMELIA_TEST(testUnit, "number_sort", number_sort);
}

void TemeliaPerformance::pt_sort(void)
{
	TestUnit testUnit("sort");

	sort_init(test_size[ntests - 1]);

	temelia_bubble_sort(testUnit, 7);
	temelia_merge_sort(testUnit, 15);
	temelia_insertion_sort(testUnit, 8);
	temelia_quick_sort(testUnit, 15);
	temelia_selection_sort(testUnit, 8);
	temelia_shell_sort(testUnit, 15);
	temelia_heap_sort(testUnit, 15);
	temelia_gnome_sort(testUnit, 7);
	temelia_cocktail_sort(testUnit, 7);
	temelia_radix_sort(testUnit, 15);
	temelia_number_sort(testUnit, 15);

	sort_destroy();

	testUnit.write(fout);
}
